package com.kasax.plugin.app.transform

import com.android.build.api.transform.*
import com.android.build.gradle.internal.pipeline.TransformManager
import com.kasax.plugin.app.LogUtils
import com.kasax.plugin.app.visitor.lifecycle3.NewLifecycleClassVisitor
import org.objectweb.asm.ClassReader

import java.util.jar.JarEntry
import java.util.jar.JarFile
import java.util.jar.JarOutputStream
import org.apache.commons.io.FileUtils
class MethodLifecycleTransformV2 extends Transform {

    @Override
    String getName() {
        return "LifecycleTransformV2"
    }

    @Override
    Set<QualifiedContent.ContentType> getInputTypes() {
        return TransformManager.CONTENT_CLASS
    }

    @Override
    Set<? super QualifiedContent.Scope> getScopes() {
        return TransformManager.SCOPE_FULL_PROJECT
    }

    @Override
    boolean isIncremental() {
        return false
    }

    @Override
    void transform(TransformInvocation transformInvocation) throws TransformException, InterruptedException, IOException {
        LogUtils.d(getName(), "------------ ------------  transform 开始  ------------ ------------  ")
        def inputs = transformInvocation.inputs
        def outputs = transformInvocation.outputProvider
        inputs.each { TransformInput input ->
            input.directoryInputs.each { DirectoryInput directoryInput ->
                def destDir = outputs.getContentLocation(
                        directoryInput.name,
                        directoryInput.contentTypes,
                        directoryInput.scopes,
                        Format.DIRECTORY
                )
                processDirecotry(directoryInput.file, destDir)
            }
            input.jarInputs.each { JarInput jarInput ->
                def destDir = outputs.getContentLocation(
                        jarInput.name,
                        jarInput.contentTypes,
                        jarInput.scopes,
                        Format.JAR
                )
                processJar(jarInput.file, destDir)
            }
        }
        LogUtils.d(getName(), "------------ ------------  transform 结束  ------------ ------------  ")
    }

    void processDirecotry(File inputDir, File outputDir) {
        LogUtils.d(getName(), "processDirecotry source-file-path: $inputDir.absolutePath , dest-file-path: $outputDir.absolutePath")

        if (outputDir.exists()) FileUtils.cleanDirectory(outputDir)

        inputDir.eachFileRecurse { File file ->
            if (file.name.endsWith(".class")) {
                File outputFile = new File(outputDir, file.absolutePath.replace(inputDir.absolutePath, ""))
                if (!outputFile.parentFile.exists()) outputFile.parentFile.mkdirs()

                byte[] modifiedClass = processClass(file.bytes)
                if (modifiedClass != null) {
                    FileUtils.writeByteArrayToFile(outputFile, modifiedClass)
                } else {
                    FileUtils.copyFile(file, outputFile)
                }
            }
        }

    }

    void processJar(File inputJar, File outputDir) {
        LogUtils.d(getName(), "processJar source-jarfile-path: $inputJar.absolutePath , dest-file-path: " +
                "$outputDir.absolutePath")
        if (!outputDir.parentFile.exists()) {
            outputDir.parentFile.mkdirs()
        }

        // 解压JAR处理class文件后重新打包
        def jarFile = new JarFile(inputJar)
        def outputJarStream = new JarOutputStream(new FileOutputStream(outputDir))
        jarFile.entries().each { JarEntry jarEntry ->
            if (!jarEntry.name.endsWith(".class")) {
                outputJarStream.putNextEntry(new JarEntry(jarEntry.name))
                outputJarStream.write(jarFile.getInputStream(jarEntry).bytes)
                outputJarStream.closeEntry()
            } else {
                def modifiedClass = processClass(jarFile.getInputStream(jarEntry).bytes)
                if (modifiedClass != null) {
                    outputJarStream.putNextEntry(new JarEntry(jarEntry.name))
                    outputJarStream.write(modifiedClass)
                    outputJarStream.closeEntry()
                }
            }
        }
        outputJarStream.close()
        jarFile.close()
    }


    byte[] processClass(byte[] classBytes) {
        // 使用ASM处理字节码
        if (classBytes == null) return null
        // 排除 DialogFragment 类
        String className = getClassName(classBytes)
        if (className != null && className.contains("androidx/fragment/app/DialogFragment")) {
            return classBytes
        }
        return NewLifecycleClassVisitor.processClass(classBytes)
    }

    private String getClassName(byte[] classBytes) {
        try {
            ClassReader classReader = new ClassReader(classBytes)
            return classReader.getClassName()
        } catch (Exception e) {
            LogUtils.e(getName(), "Failed to parse class name", e)
            return null
        }
    }
}